<template>
  <div class="dashboard-container">
    <div class="app-container">
      <page-tools>
        <template #before>共{{ page.total }}条记录</template>
        <template #after>
          <!-- query.type 是为了让公共的导入页面识别要导入的类型 -->
          <el-button
            v-btnCheck.disabled="'employees_import'"
            size="small"
            type="warning"
            @click="$router.push({ name: 'Import', query: { type: 'employee' } })"
          >
            导入
          </el-button>
          <el-button size="small" type="danger" @click="exportData">导出</el-button>
          <el-button size="small" type="primary" @click="$refs.addEmployeeDialog.visible = true">新增员工</el-button>
        </template>
      </page-tools>

      <el-card>
        <el-table border :data="list" v-loading="loading">
          <el-table-column type="index" label="序号" sortable width="50" align="center" />
          <el-table-column label="姓名" sortable prop="username" />
          <el-table-column label="头像" sortable #default="{ row }" align="center" width="120">
            <el-avatar :size="80" :src="row.staffPhoto" @click.native="showQrCode(row.staffPhoto)">
              <!-- 默认插槽，什么时候生效呢？ 当 上面的 src 没有值，或者给的值是一个错误的图片地址，就会显示这个默认插槽的内容 -->
              <!-- 下面这两种方式都是错的，不能找到正确的图片路径 -->
              <!-- <img src="/assets/common/head.jpg" alt="" /> -->
              <!-- <img src="@/assets/common/head.jpg" alt="" /> -->
              <!-- 只用通过 require 去引用，才能经过 webpack 的解析，才能识别 @ 为 src -->
              <img :src="require('@/assets/common/head.jpg')" alt="" />
            </el-avatar>
          </el-table-column>
          <el-table-column label="工号" sortable prop="workNumber" />
          <el-table-column label="手机号" sortable prop="mobile" />
          <el-table-column label="聘用形式" sortable prop="formOfEmploymentFormat" />
          <el-table-column label="部门" sortable prop="departmentName" />
          <el-table-column label="入职时间" sortable prop="timeOfEntry" #default="{ row }">
            {{ row.timeOfEntry | formatDate }}
          </el-table-column>
          <el-table-column label="账户状态" sortable prop="enableState" #default="{ row }">
            <el-switch :value="Number(row.enableState) === 1" />
            {{ Number(row.enableState) === 1 ? '激活' : '冻结' }}
          </el-table-column>
          <el-table-column label="操作" sortable fixed="right" width="280" #default="{ row }">
            <!-- 跳到另外一个页面之前，先将信息保存到自己的路由信息对象 this.$route 的 meta 中 -->
            <!-- 回来的时候，路由信息对象上就有，直接取就行了 -->
            <el-button
              type="text"
              size="small"
              @click="$router.push({ name: 'employee/detail', params: { id: row.id } })"
            >
              查看
            </el-button>
            <el-button type="text" size="small">转正</el-button>
            <el-button type="text" size="small">调岗</el-button>
            <el-button type="text" size="small">离职</el-button>
            <el-button type="text" size="small" @click="openRoleDialog(row, $event)" :loading="row.loadingOfRole"
              >角色</el-button
            >
            <el-button type="text" size="small" @click="delEmployee(row)">删除</el-button>
          </el-table-column>
        </el-table>
        <!-- 分页组件 -->
        <div style="margin-top: 20px; display: flex; justify-content: flex-end">
          <el-pagination
            :total="page.total"
            :current-page.sync="page.page"
            :page-size.sync="page.size"
            @current-change="getEmployeeList"
            layout="prev, pager, next"
          />
        </div>
      </el-card>
    </div>

    <AddEmployeeDialog ref="addEmployeeDialog" @add-succ="addEmployeeSucc" />

    <el-dialog :visible.sync="showDialogOfAvatarQrCode" title="二维码" width="300px">
      <div style="display: flex; justify-content: center">
        <canvas ref="avatarQrCodeCanvas"></canvas>
      </div>
    </el-dialog>

    <el-dialog :visible.sync="showDialogOfRole" :title="roleDialogTitle">
      <el-form label-width="120px">
        <el-form-item label="角色列表：">
          <el-checkbox-group v-model="curUserRoleIds">
            <!-- label  -->
            <el-checkbox v-for="v of roleList" :key="v.id" :label="v.id">{{ v.name }}</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onOkOfRoleDialog">确定</el-button>
          <el-button @click="showDialogOfRole = false">取消</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import { getEmployeeList, delEmployee, saveUserDetailById } from '@/api/employees';
import EmployeesEnum from '@/api/constant/employees';
import AddEmployeeDialog from './components/AddEmployeeDialog';
import { formatDate } from '@/filters';
import { getRoleList } from '@/api/setting';
import { getDetailUserInfo } from '@/api/user';
import { sameArrayValue } from '@/utils';

import QrCode from 'qrcode';

export default {
  name: 'Employees',
  components: { AddEmployeeDialog },
  data() {
    return {
      // [ 角色对象框相关的数据
      curUser: null, // 当前操作的用户
      roleDialogTitle: '分配角色',
      curUserRoleIds: [], // 当前选中的用户的角色列表
      roleList: [], // 可选的角色列表
      showDialogOfRole: false,
      // ] 角色对象框相关的数据

      showDialogOfAvatarQrCode: false,
      list: [],
      page: {
        page: 1,
        size: 10,
        total: 0,
      },
      loading: false,
    };
  },
  methods: {
    // [ 分配角色对话框相关的方法
    async onOkOfRoleDialog() {
      // 如果 角色列表 没有变动，那就不需要发请求
      if (sameArrayValue(this.curUser.roleIds, this.curUserRoleIds, true)) {
        this.$message.warning('你没有做修改哦~');
      } else {
        this.curUser.roleIds = this.curUserRoleIds;
        await saveUserDetailById(this.curUser);
        this.$message.success('角色分配成功');
        this.showDialogOfRole = false;
      }
    },

    async openRoleDialog(user) {
      user.loadingOfRole = true;
      this.curUser = user;

      try {
        const { rows } = await getRoleList({ page: 1, pagesize: 9999 });
        this.roleList = rows || [];

        const { roleIds } = await getDetailUserInfo(user.id);
        this.curUserRoleIds = roleIds || [];
        // 这里必须浅拷贝，不然  赋的是内存地址，怎么的 都一样
        this.curUser.roleIds = [...this.curUserRoleIds];

        this.roleDialogTitle = `分配角色-${user.username}`;
        this.showDialogOfRole = true;
      } finally {
        user.loadingOfRole = false;
      }
    },
    // ] 分配角色对话框相关的方法
    showQrCode(avatarUrl) {
      this.showDialogOfAvatarQrCode = true;
      this.$nextTick(() => {
        QrCode.toCanvas(this.$refs.avatarQrCodeCanvas, avatarUrl);
      });
    },
    // 格式化json数据
    // rows [{},{},{},{}] => [[],[],[],[]]
    formatJson(headers, rows) {
      // 对第一层的数组进行遍历
      // {
      //             "id": "604f764971f93f3ac8f365c2",
      //             "mobile": "13800000002",
      //             "username": "管理员3",
      //             "password": "e10adc3949ba59abbe56e057f20f883e",
      //             "timeOfEntry": "2018-11-02",
      //             "formOfEmployment": 1,
      //             "workNumber": "9002",
      //             "correctionTime": "2018-11-30",
      //             "departmentName": "总裁办",
      //             "staffPhoto": "http://q6cu3t6jv.bkt.clouddn.com/1063705989926227968?t=1616204161907"
      //         }
      // 转化成
      // ["604f764971f93f3ac8f365c2","13800000002", "管理员3"]
      // [[],[],[]]

      // 在这里也可以处理日期格式的数据

      // return rows.map(item => {
      //   //   Object.values(headers) ['username', 'mobile', 'formOfEmployment']
      //   // ["604f764971f93f3ac8f365c2","13800000002", "管理员3"]
      //   return Object.values(headers).map(value => {
      //     // 此时value就是 字段名
      //     // item[value] 对应的就是 13800000002 -管理员3 -2018-11-02
      //     return item[value];
      //   });
      // });

      return rows.map(item => Object.values(headers).map(value => item[value]));
    },
    async exportData() {
      // 动态导入 这个 导出Excel组件（Export2Excel）
      const excel = await import('@/vendor/Export2Excel');

      // 定义对应关系- 把英文的key转化成中文的key所对应的值
      const headers = {
        姓名: 'username',
        手机: 'mobile',
        入职日期: 'timeOfEntry',
        聘用形式: 'formOfEmployment',
        转正日期: 'correctionTime',
        工号: 'workNumber',
        部门: 'departmentName',
      };

      const { rows } = await getEmployeeList({ page: 1, size: this.page.total });
      // rows就是所有的数据 rows [{},{},{}] => [[],[],[],[]]

      // 可以在这里先把日期格式的数据处理好
      for (const v of rows) {
        v.timeOfEntry = v.timeOfEntry && formatDate(v.timeOfEntry);
        v.correctionTime = v.correctionTime && formatDate(v.correctionTime);
        const obj = EmployeesEnum.hireType.find(v2 => v2.id === v.formOfEmployment);
        v.formOfEmployment = obj?.value || '未知';
      }

      const data = this.formatJson(headers, rows); // 转化数据表结构

      for (const [i, v] of data.entries()) {
        v.unshift(i + 1);
      }

      data.push(['姓高的', `${data.filter(v => v[1].startsWith('高')).length}个`]);

      excel.export_json_to_excel({
        multiHeader: [['序号', '姓名', '主要信息', '', '', '', '', '部门']],
        header: ['序号', ...Object.keys(headers)],
        merges: ['A1:A2', 'B1:B2', 'C1:G1', 'H1:H2'],
        data,
        filename: 'ihrm人力资源用户表', // 非必填
        autoWidth: true, // 非必填
        bookType: 'xlsx', // 非必填
      });
    },
    async addEmployeeSucc() {
      this.$message.success('添加成功');
      await this.getEmployeeList();
    },
    async delEmployee(row) {
      await this.$confirm(`你确定要删除 "${row.username}" 吗？`, '提示', { type: 'warning' });
      await delEmployee(row.id);
      this.$message.success('删除成功');

      // 如果删除的是当前页最后一条数据，并且不在第一页，那么就将当前页码-1，去加载上一页数据
      if (this.list.length === 1 && this.page.page > 1) {
        this.page.page--;
      }

      await this.getEmployeeList();
    },
    async getEmployeeList() {
      this.loading = true;
      try {
        const { total, rows } = await getEmployeeList(this.page);

        if (rows.length === 0 && this.page.page !== 1) {
          this.page.page--;
          this.getEmployeeList();
        } else {
          // fk~~~~
          this.page.total = total;

          // [ 格式化聘用形式
          for (const v of rows) {
            const obj = EmployeesEnum.hireType.find(v2 => v2.id === Number(v.formOfEmployment));
            v.formOfEmploymentFormat = obj ? obj.value : '未知';
          }
          // ] 格式化聘用形式

          // 因为如果在赋值的时候没有这个属性，Vue就监听不到了
          // 因为在赋值时，会触发 set 取值函数，Vue 就是在 set 函数中做的数据劫持，如果在赋值时，没有这个属性，
          // 那么 Vue 在做数据劫持的时候，就不会劫持到这个属性
          // list 改变时，会被劫持到，然后，Vue 会判断数据类型，如果数组中的元素是对象，会递归进行劫持
          this.list = rows;

          for (const row of rows) {
            // 这样赋值，不会触发 set 取值函数，因为在此之前，没有对该属性做 set 取值函数描述符 配置
            // row.loadingOfRole = false;

            // 下面两个方法，是 Vue 提供给开发者 在 动态添加属性时，支持响应式的 API
            // Vue.set
            // this.$set
            this.$set(row, 'loadingOfRole', false);
          }
        }
      } finally {
        this.loading = false;
      }
    },
  },
  async created() {
    if (this.$route.meta.page) {
      this.page = this.$route.meta.page;
    }

    await this.getEmployeeList();
  },
  beforeRouteLeave(to, from, next) {
    // 走之前，先将分页数据挂到路由信息对象上
    from.meta.page = this.page;
    next();
  },
};
</script>
